package ws

import (
	"github.com/gorilla/websocket"
	"net"
	"net/http"
	"runtime"
	"sync"
	"time"
)

type Hub struct {
	debug bool

	// Clients 存储链接到server的client链接,根据客户端传过来的"Sec-WebSocket-Key"确定是哪一个客户端
	Clients map[string]*net.Conn

	// HeartBeatInterval 心跳间隔，单位s 默认10s
	HeartBeatInterval int64
	// HeartBeatTimeOut 心跳间隔超时阈值，单位s 默认10s,超过这个时间则应该主动发起心跳进行检测
	HeartBeatTimeOut int64
	// HeartBeatTimeKill 链接丢失判定阈值，单位s 默认30s,超过这个时间则认为这个链接已经废弃，应该进行关闭相关的处理
	HeartBeatTimeKill int64

	Sessions map[string]*Session
	LK       sync.Mutex

	//群发时，设定一个最大值，当群发超过这个最大值时，分批群发，并且适当延迟邓艾
	MaxBroadCastCount int //群发阈值
	MaxBroadCastSleep int //群发休眠值，单位毫秒，ms
}

var ezhub *Hub

func NewHub() *Hub {
	ezhub = &Hub{
		debug:             true,
		Sessions:          make(map[string]*Session),
		LK:                sync.Mutex{},
		HeartBeatInterval: 3,
		HeartBeatTimeOut:  10,
		HeartBeatTimeKill: 30,
		MaxBroadCastCount: 1000,
		MaxBroadCastSleep: 100,
	}
	return ezhub
}

func (hub *Hub) Upgrade(writer http.ResponseWriter, request *http.Request) {
	conn, err := Upgrd.Upgrade(writer, request, http.Header{})

	if hub.handleErr(err) {
		return
	}
	session := &Session{
		Id:     request.Header.Get("Sec-WebSocket-Key"),
		Conn:   conn,
		Closer: make(chan int),
		Locker: sync.Mutex{},
	}
	defer conn.Close()
	hub.RegSession(session)
	go hub.checkClientAlive(session)
	go hub.readMessage(session)
	<-session.Closer
	//执行一些收尾的动作，资源释放，全局数据删除等
	hub.RemoveSession(session)
	//从UserSessions中删除
	RemoveSessionFromUser(session)
}

func (hub *Hub) readMessage(session *Session) {
	for {
		mt, content, errMsg := session.Conn.ReadMessage()
		if hub.handleErr(errMsg) {
			session.close()
			hub.RemoveSession(session)
			return
		}
		//成功收到消息后更新心跳时间，避免重复无意义的心跳请求
		now := time.Now().Unix()
		session.HeartBeatTime = now

		response := hub.handleMessage(session, mt, content)
		if response.Silent {
			//做一些静默处理的事情
		} else {
			session.Locker.Lock()
			errWrite := session.Conn.WriteMessage(websocket.TextMessage, response.Content)
			session.Locker.Unlock()
			if hub.handleErr(errWrite) {
				session.close()
				return
			}
		}
	}
}

func (hub *Hub) handleErr(err error) bool {
	if err != nil {
		_, f, l, _ := runtime.Caller(1)
		println(f, l, err.Error())
		return true
	}
	return false
}

func (hub *Hub) handleMessage(session *Session, messageType int, content []byte) *Response {
	if messageType == websocket.TextMessage {
		//心跳检测
		if string(content) == "ping" {
			return NewTextResponse("pong")
		}
		if string(content) == "pong" {
			//心跳响应
			//todo 保鲜机制
			return NewSilentResponse()
		}
		//格式化数据
		req := NewRequest()
		req.Decode(content)
		switch req.Business {
		case BusinessReg:
			//注册用户
			session.User = req.Content
			hub.RegUser(session)
		case BusinessLogout:
			//注销用户
			println(req.Content)
		default:
			println("com", req.Content)
		}
	}
	return NewSilentResponse()
}
